﻿using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PT.NoteDetection.Util;

namespace PT.NoteDetection.Tests {
    /// <summary>
    /// This is a test class for CircularArrayQueueTest and is intended
    /// to contain all CircularArrayQueueTest Unit Tests
    ///</summary>
    [TestClass]
    public class CircularArrayQueueTest {

        /// <summary>
        /// Gets or sets the test context which provides
        /// information about and functionality for the current test run.
        /// </summary>
        public TestContext TestContext { get; set; }

        [TestMethod]
        public void AddTest() {
            const int capacity = 3;
            var target = new CircularArrayQueue<float>(capacity);

            Assert.AreEqual(capacity, target.Capacity);
            Assert.AreEqual(0, target.Count);
            Assert.IsTrue(target.IsEmpty);

            for(int i = 0; i < target.Capacity; ++i){
                target.Add(Convert.ToSingle(i));
                Assert.AreEqual(i+1, target.Count);
                Assert.IsFalse(target.IsEmpty);
            }

            Assert.IsTrue(target.IsFull);

            target.Add(9f);
            Assert.AreEqual(capacity, target.Count);
        }

        [TestMethod]
        public void RemoveTest() {
            const int capacity = 3;
            var target = new CircularArrayQueue<float>(capacity);

            Assert.AreEqual(0, target.Count);
            Assert.IsTrue(target.IsEmpty);
            Assert.IsFalse(target.IsFull);

            target.Add(1f);
            Assert.IsFalse(target.IsEmpty);

            target.Remove();
            Assert.IsTrue(target.IsEmpty);

            for (int i = 0; i < 2 * target.Capacity; ++i) {
                target.Add(i);
            }
            Assert.IsFalse(target.IsEmpty);
            Assert.IsTrue(target.IsFull);
            Assert.AreEqual(target.Capacity, target.Count);

            for (int i = 0; i < target.Capacity; ++i) {
                target.Remove();
            }

            Assert.IsTrue(target.IsEmpty);
        }

        [TestMethod]
        public void GetEnumeratorTest() {
            var values = new [] { 0.01f, 0.02f, 0.03f, 0.04f, 0.05f };
            var target = new CircularArrayQueue<float>(values.Length);

            foreach (var value in values) {
                target.Add(value);
	        }

            // Should be in order as inserted 
            int i = 0;
            foreach (var insertedValue in target) {
                Assert.AreEqual(values[i++], insertedValue, "Inserted values are out of order");
            }
        }

        [TestMethod]
        public void ItemTest() {

            var v = new [] { 0.01f, 0.02f, 0.03f, 0.04f, 0.05f };
            var target = new CircularArrayQueue<float>(v.Length);

            Assert.IsTrue(target.IsEmpty);

            foreach (var val in v) {
                target.Add(val);

                for (int i = 0; i < target.Count; ++i){
                    Assert.AreEqual(v[i], target[i]);
                }
            }

            Assert.IsTrue(target.IsFull);

            // Add another value. Since buffer size is 5,
            // this should replace the oldest value (inserted from values[0]). 
            const float newValue = 0.06f;
            target.Add(newValue);
            Assert.AreEqual(newValue, target[target.Count - 1]);
            v[0] = newValue;

            // Check the other values
            for (int i = 1; i < v.Length; i++) {
                Assert.AreEqual(v[i], target[i - 1]);
            }

            // Remove two elements. This should remove t[0]=v[1] and t[1]=v[2]
            target.Remove();
            target.Remove();
            
            Assert.AreEqual(3, target.Count);

            for (int i = 0; i < target.Count; i++) {
                Assert.AreEqual(v[(3 + i) % v.Length], target[i]);
            }
        }
    }
}
